﻿using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;

namespace Soul.IdentityServer.Services
{
    internal class DiscoveryService : IDiscoveryService
    {
        private readonly IdentityServiceOptions _options;
        private readonly IGrantValidatorFactory _grantService;
        private readonly IResourceStore _resourceStore;
        private readonly IHttpContextAccessor _httpContextAccessor;

        public DiscoveryService(IdentityServiceOptions options, IGrantValidatorFactory grantService, IHttpContextAccessor httpContextAccessor, IResourceStore resourceStore)
        {
            _options = options;
            _grantService = grantService;
            _resourceStore = resourceStore;
            _httpContextAccessor = httpContextAccessor;
        }
       
        public string Issuer
        {
            get
            {
                if (!string.IsNullOrEmpty(_options.Issuer))
                {
                    return _options.Issuer;
                }
                return BaseUri;
            }
        }

        public string BaseUri
        {
            get
            {
                var request = _httpContextAccessor.HttpContext!.Request;
                var url = request.Scheme + "://" + request.Host.ToUriComponent();
                if (url.EndsWith("/"))
                    url = url[0..^1];
                return url;
            }
        }

        public string JwksUri
        {
            get
            {
                return $"{BaseUri}{OpenIdConnectEndpoints.DiscoveryJwks}";
            }
        }

        public string TokenEndpoint
        {
            get
            {
                return $"{BaseUri}{_options.EndpointPathPrefix}{OpenIdConnectEndpoints.Token}";
            }
        }

        public string RevocationEndpoint
        {
            get
            {
                return $"{BaseUri}{_options.EndpointPathPrefix}{OpenIdConnectEndpoints.Revocation}";
            }
        }

        public string UserInfoEndpoint
        {
            get
            {
                return $"{BaseUri}{_options.EndpointPathPrefix}{OpenIdConnectEndpoints.UserInfo}";
            }
        }

        public string EndSessionEndpoint
        {
            get
            {
                return $"{BaseUri}{_options.EndpointPathPrefix}{OpenIdConnectEndpoints.EndSession}";
            }
        }

        public string AuthorizationEndpoint
        {
            get
            {
                return $"{BaseUri}{_options.EndpointPathPrefix}{OpenIdConnectEndpoints.Authorize}";
            }
        }

        public string IntrospectionEndpoint
        {
            get
            {
                return $"{BaseUri}{_options.EndpointPathPrefix}{OpenIdConnectEndpoints.Introspection}";
            }
        }

        public async Task<OpenIdConnectConfiguration> GetOpenIdConnectConfigurationAsync()
        {
            var configuration = new OpenIdConnectConfiguration
            {
                Issuer = Issuer,
                JwksUri = JwksUri,
                TokenEndpoint = TokenEndpoint,
                UserInfoEndpoint = UserInfoEndpoint,
                EndSessionEndpoint = EndSessionEndpoint,
                AuthorizationEndpoint = AuthorizationEndpoint,
                IntrospectionEndpoint = IntrospectionEndpoint,
            };
            configuration.AdditionalData.Add("revocation_endpoint", RevocationEndpoint);
            foreach (var item in _grantService.SupportedGrantTypes)
            {
                configuration.GrantTypesSupported.Add(item);
            }
            foreach (var item in await _resourceStore.GetSupportedScopesAsync())
            {
                configuration.ScopesSupported.Add(item);
            }
            return configuration;
        }
    }
}
